#ifdef USE_EMAIL
/*
 * EMail Sender Arduino, esp8266 and esp32 library to send email
 *
 * AUTHOR:  Renzo Mischianti
 * VERSION: 2.3.0
 *
 * https://www.mischianti.org/
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Renzo Mischianti www.mischianti.org All right reserved.
 *
 * You may copy, alter and reuse this code in any way you like, but please leave
 * reference to www.mischianti.org in your comments if you redistribute this code.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <rtos.h>
#include "EMailSender.h"
//#include <SPIFFS.h>
//#include <LittleFS.h>

//#define SD SPIFFS

// BASE64 -----------------------------------------------------------
const char PROGMEM b64_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                                    "abcdefghijklmnopqrstuvwxyz"
                                    "0123456789+/";

#define encode64(arr) encode64_f(arr,strlen(arr))

inline void a3_to_a4(unsigned char *a4, const unsigned char *a3) {
    a4[0] = (a3[0] & 0xfc) >> 2;
    a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4);
    a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6);
    a4[3] = (a3[2] & 0x3f);
}

static int base64_encode(char *output, char *input, int inputLen) {
    int i = 0, j;
    int encLen = 0;
    unsigned char a3[3];
    unsigned char a4[4];

    while (inputLen--) {
        a3[i++] = *(input++);
        if (i == 3) {
            a3_to_a4(a4, a3);

            for (i = 0; i < 4; i++) {
                output[encLen++] = pgm_read_byte(&b64_alphabet[a4[i]]);
            }

            i = 0;
        }
    }

    if (i) {
        for (j = i; j < 3; j++) {
            a3[j] = '\0';
        }

        a3_to_a4(a4, a3);

        for (j = 0; j < i + 1; j++) {
            output[encLen++] = pgm_read_byte(&b64_alphabet[a4[j]]);
        }

        while (i++ < 3) {
            output[encLen++] = '=';
        }
    }
    output[encLen] = '\0';
    return encLen;
}

int base64_enc_length(int plainLen) {
    int n = plainLen;
    return (n + 2 - ((n + 2) % 3)) / 3 * 4;
}

const char *encode64_f(char *input, uint8_t len) {
    // encoding

    DEBUG_PRINTLN(F("Encoding"))

    DEBUG_PRINTLN(input)
    DEBUG_PRINTLN(len)

    //int encodedLen =
    base64_enc_length(len);
    static char encoded[256];
    // note input is consumed in this step: it will be empty afterwards
    base64_encode(encoded, input, len);
    return encoded;
}

// END BASE64 ---------------------------------------------------------

EMailSender::EMailSender(const char *email_login, const char *email_password, const char *email_from,
                         const char *name_from,
                         const char *smtp_server, uint16_t smtp_port) {
    this->setEMailLogin(email_login);
    this->setEMailFrom(email_from);
    this->setEMailPassword(email_password);
    this->setSMTPServer(smtp_server);
    this->setSMTPPort(smtp_port);
    this->setNameFrom(name_from);
//	this->isSecure = isSecure;
}

EMailSender::EMailSender(const char *email_login, const char *email_password, const char *email_from,
                         const char *smtp_server, uint16_t smtp_port) {
    this->setEMailLogin(email_login);
    this->setEMailFrom(email_from);
    this->setEMailPassword(email_password);
    this->setSMTPServer(smtp_server);
    this->setSMTPPort(smtp_port);

//	this->isSecure = isSecure;
}

EMailSender::EMailSender(const char *email_login, const char *email_password, const char *email_from,
                         const char *name_from) {
    this->setEMailLogin(email_login);
    this->setEMailFrom(email_from);
    this->setEMailPassword(email_password);
    this->setNameFrom(name_from);
    this->setNameFrom(name_from);

//	this->isSecure = isSecure;
}

EMailSender::EMailSender(const char *email_login, const char *email_password, const char *email_from) {
    this->setEMailLogin(email_login);
    this->setEMailFrom(email_from);
    this->setEMailPassword(email_password);

//	this->isSecure = isSecure;
}

EMailSender::EMailSender(const char *email_login, const char *email_password) {
    this->setEMailLogin(email_login);
    this->setEMailFrom(email_login);
    this->setEMailPassword(email_password);

//	this->isSecure = isSecure;
}

void EMailSender::setSMTPPort(uint16_t smtp_port) {
    this->smtp_port = smtp_port;
}

void EMailSender::setSMTPServer(const char *smtp_server) {
    delete[] this->smtp_server;
    this->smtp_server = new char[strlen(smtp_server) + 1];
    strcpy(this->smtp_server, smtp_server);
}

void EMailSender::setEMailLogin(const char *email_login) {
    delete[] this->email_login;
    this->email_login = new char[strlen(email_login) + 1];
    strcpy(this->email_login, email_login);
}

void EMailSender::setEMailFrom(const char *email_from) {
    delete[] this->email_from;
    this->email_from = new char[strlen(email_from) + 1];
    strcpy(this->email_from, email_from);
}

void EMailSender::setNameFrom(const char *name_from) {
    delete[] this->name_from;
    this->name_from = new char[strlen(name_from) + 1];
    strcpy(this->name_from, name_from);
}

void EMailSender::setEMailPassword(const char *email_password) {
    delete[] this->email_password;
    this->email_password = new char[strlen(email_password) + 1];
    strcpy(this->email_password, email_password);
}

void EMailSender::setIsSecure(bool isSecure) {
    this->isSecure = isSecure;
}

EMailSender::Response EMailSender::awaitSMTPResponse(EMAIL_NETWORK_CLASS &client,                                                     int resp, const char *respDesc, uint16_t timeOut) {
    EMailSender::Response response;
    uint32_t ts = millis();
    while (!client.available()) {
        if (millis() > (ts + timeOut)) {
            response.code = 1;
            response.desc = F("SMTP Response TIMEOUT!");
            response.status = false;
            return response;
        }
        rtos::Delay(1);
    }
    _serverResponce = client.readStringUntil('\n');

    DEBUG_PRINTLN(_serverResponce)
    if (resp && _serverResponce.indexOf(resp) == -1) {
        response.code = resp;
        response.desc = respDesc + String(" (") + _serverResponce + String(")");
        response.status = false;
        return response;
    }

    response.status = true;
    return response;
}

static const char cb64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

void encodeblock(const unsigned char in[3], unsigned char out[4], int len) {
    out[0] = cb64[in[0] >> 2];
    out[1] = cb64[((in[0] & 0x03) << 4) | ((in[1] & 0xF0) >> 4)];
    out[2] = (unsigned char) (len > 1 ? cb64[((in[1] & 0x0F) << 2) | ((in[2] & 0xC0) >> 6)] : '=');
    out[3] = (unsigned char) (len > 2 ? cb64[in[2] & 0x3F] : '=');
}

#ifdef ENABLE_ATTACHMENTS
#if (defined(STORAGE_INTERNAL_ENABLED) && defined(FS_NO_GLOBALS))
void encode(fs::File *file, EMAIL_NETWORK_CLASS *client) {
 unsigned char in[3],out[4];
 int i,len,blocksout=0;

 while (file->available()!=0) {
   len=0;
     for (i=0;i<3;i++){
           in[i]=(unsigned char) file->read();
               if (file->available()!=0) len++;
                     else in[i]=0;
     }
     if (len){
         encodeblock(in,out,len);
//         for(i=0;i<4;i++) client->write(out[i]);
         client->write(out, 4);
         blocksout++; }
     if (blocksout>=19||file->available()==0){
         if (blocksout) {
             client->print("\r\n");
         }
         blocksout=0;
     }
  }
}
#endif

#if (defined(STORAGE_SD_ENABLED) || (defined(STORAGE_INTERNAL_ENABLED) && !defined(FS_NO_GLOBALS)))

void encode(FlashFile *file, EMAIL_NETWORK_CLASS *client) {
    unsigned char in[3], out[4];
    int len, blocksout = 0;

    while (file->available() != 0) {
        len = 0;
        for (unsigned char &i: in) {
            i = (unsigned char) file->read();
            if (file->available() != 0) len++;
            else i = 0;
        }
        if (len) {
            encodeblock(in, out, len);
            //         for(i=0;i<4;i++) client->write(out[i]);
            client->write(out, 4);
            blocksout++;
        }
        if (blocksout >= 19 || file->available() == 0) {
            if (blocksout) {
                client->print("\r\n");
            }
            blocksout = 0;
        }
    }
}

#endif
#endif

const char **toCharArray(String arr[], int num) {
    // If we ever alloc with new with have to delete
    const auto **buffer = new const char *[num];

    for (int i = 0; i < num; i++) {
        buffer[i] = arr[i].c_str();
    }

    return buffer;
}

const char **toCharArray(char *arr[], int num) {
    // If we ever alloc with new with have to delete
    const auto **buffer = new const char *[num];

    for (int i = 0; i < num; i++) {
        buffer[i] = arr[i];
    }

    return buffer;
}

EMailSender::Response EMailSender::send(char *tos[], byte sizeOfTo, EMailMessage &email, Attachments attachments) {
    return send(toCharArray(tos, sizeOfTo), sizeOfTo, 0, 0, email, attachments);
}

EMailSender::Response
EMailSender::send(char *tos[], byte sizeOfTo, byte sizeOfCc, EMailMessage &email, Attachments attachments) {
    return send(toCharArray(tos, sizeOfTo + sizeOfCc), sizeOfTo, sizeOfCc, 0, email, attachments);
}

EMailSender::Response EMailSender::send(char *tos[], byte sizeOfTo, byte sizeOfCc, byte sizeOfCCn, EMailMessage &email,
                                        Attachments attachments) {
    return send(toCharArray(tos, sizeOfTo + sizeOfCc + sizeOfCCn), sizeOfTo, sizeOfCc, sizeOfCCn, email, attachments);
}


EMailSender::Response EMailSender::send(const String &to, EMailMessage &email, Attachments attachments) {
    DEBUG_PRINT(F("ONLY ONE RECIPIENT"))

    const char *arrEmail[] = {to.c_str()};
    return send(arrEmail, 1, email, attachments);
}

EMailSender::Response EMailSender::send(String tos[], byte sizeOfTo, EMailMessage &email, Attachments attachments) {
    return send(toCharArray(tos, sizeOfTo), sizeOfTo, 0, 0, email, attachments);
}

EMailSender::Response
EMailSender::send(String tos[], byte sizeOfTo, byte sizeOfCc, EMailMessage &email, Attachments attachments) {
    return send(toCharArray(tos, sizeOfTo + sizeOfCc), sizeOfTo, sizeOfCc, 0, email, attachments);
}

EMailSender::Response EMailSender::send(String tos[], byte sizeOfTo, byte sizeOfCc, byte sizeOfCCn, EMailMessage &email,
                                        Attachments attachments) {
    return send(toCharArray(tos, sizeOfTo + sizeOfCc + sizeOfCCn), sizeOfTo, sizeOfCc, sizeOfCCn, email, attachments);
}

EMailSender::Response EMailSender::send(const char *to, EMailMessage &email, Attachments attachments) {
    DEBUG_PRINT(F("ONLY ONE RECIPIENT"))

    const char *arrEmail[] = {to};
    return send(arrEmail, 1, email, attachments);
}

EMailSender::Response EMailSender::send(const char *to[], byte sizeOfTo, EMailMessage &email, Attachments attachments) {
    DEBUG_PRINTLN(F("miltiple destination and attachments"))
    return send(to, sizeOfTo, 0, email, attachments);
}

EMailSender::Response
EMailSender::send(const char *to[], byte sizeOfTo, byte sizeOfCc, EMailMessage &email, Attachments attachments) {
    return send(to, sizeOfTo, sizeOfCc, 0, email, attachments);
}

EMailSender::Response
EMailSender::send(const char *to[], byte sizeOfTo, byte sizeOfCc, byte sizeOfCCn, EMailMessage &email,
                  Attachments attachments) {
    EMAIL_NETWORK_CLASS client;
//	SSLClient client(base_client, TAs, (size_t)TAs_NUM, A5);

    DEBUG_PRINT(F("Insecure client:"))
    DEBUG_PRINTLN(this->isSecure)

#if (EMAIL_NETWORK_TYPE == NETWORK_ESP8266 || EMAIL_NETWORK_TYPE == NETWORK_ESP8266_242)
#ifndef ARDUINO_ESP8266_RELEASE_2_4_2
    if (this->isSecure == false){
        client.setInsecure();
        bool mfln = client.probeMaxFragmentLength(this->smtp_server, this->smtp_port, 512);

        DEBUG_PRINT("MFLN supported: ");
        DEBUG_PRINTLN(mfln?"yes":"no");

        if (mfln) {
            client.setBufferSizes(512, 512);
        }
    }
#endif
#elif (EMAIL_NETWORK_TYPE == NETWORK_ESP32)
    //	  String coreVersion = String(ESP.getSdkVersion());
    //	  uint8_t firstdot = coreVersion.indexOf('.');
    //
    //	  DEBUG_PRINTLN(coreVersion.substring(1, coreVersion.indexOf('.', firstdot+1)).toFloat());
    //	  DEBUG_PRINTLN(coreVersion.substring(1, coreVersion.indexOf('.', firstdot+1)).toFloat() >= 3.3f);
    //	  if (coreVersion.substring(1, coreVersion.indexOf('.', firstdot+1)).toFloat() >= 3.3f) {
    //		  client.setInsecure();
    //	  }
#include <core_version.h>
#if ((!defined(ARDUINO_ESP32_RELEASE_1_0_4)) && (!defined(ARDUINO_ESP32_RELEASE_1_0_3)) && (!defined(ARDUINO_ESP32_RELEASE_1_0_2)))
              client.setInsecure();
#endif
#endif

    EMailSender::Response response;

    DEBUG_PRINTLN(this->smtp_server)
    DEBUG_PRINTLN(this->smtp_port)

    if (client.connect(this->smtp_server, this->smtp_port) < 0) {
        response.desc = F("Could not connect to mail server");
        response.code = 2;
        response.status = false;

        return response;
    }

    response = awaitSMTPResponse(client, 220, "Connection Error");
    if (!response.status) return response;

    String commandHELO = "HELO";
    if (this->useEHLO) {
        commandHELO = "EHLO";
    }
    String helo = commandHELO + " " + String(publicIPDescriptor) + ": ";
    DEBUG_PRINTLN(helo)
    client.println(helo);

    response = awaitSMTPResponse(client, 250, "Identification error");
    if (!response.status) return response;

    if (this->useEHLO) {
        for (int i = 0; i <= 6; i++) awaitSMTPResponse(client);
    }

    if (useAuth) {
        if (this->isSASLLogin) {

            int size = 1 + strlen(this->email_login) + strlen(this->email_password) + 2;
            auto *logPass = (char *) malloc(size);

//	      strcpy(logPass, " ");
//	      strcat(logPass, this->email_login);
//	      strcat(logPass, " ");
//	      strcat(logPass, this->email_password);

//		  String logPass;
            int maincont = 0;

            logPass[maincont++] = ' ';
            logPass[maincont++] = (char) 0;

            for (unsigned int i = 0; i < strlen(this->email_login); i++) {
                logPass[maincont++] = this->email_login[i];
            }
            logPass[maincont++] = (char) 0;
            for (unsigned int i = 0; i < strlen(this->email_password); i++) {
                logPass[maincont++] = this->email_password[i];
            }


//	      strcpy(logPass, "\0");
//	      strcat(logPass, this->email_login);
//	      strcat(logPass, "\0");
//	      strcat(logPass, this->email_password);

            String auth = "AUTH PLAIN " + String(encode64_f(logPass, size));
//		  String auth = "AUTH PLAIN "+String(encode64(logPass));
            DEBUG_PRINTLN(auth)
            client.println(auth);
        } else {
            DEBUG_PRINTLN(F("AUTH LOGIN:"))
            client.println(F("AUTH LOGIN"));
            awaitSMTPResponse(client);

            DEBUG_PRINTLN(encode64(this->email_login))
            client.println(encode64(this->email_login));
            awaitSMTPResponse(client);

            DEBUG_PRINTLN(encode64(this->email_password))
            client.println(encode64(this->email_password));
        }
        response = awaitSMTPResponse(client, 235, "SMTP AUTH error");
        if (!response.status) return response;
    }
    DEBUG_PRINT(F("MAIL FROM: <"))
    DEBUG_PRINT(this->email_from)
    DEBUG_PRINTLN(F(">"))

    client.print(F("MAIL FROM: <"));
    client.print(this->email_from);
    client.println(F(">"));
    awaitSMTPResponse(client);

//  String rcpt = "RCPT TO: <" + String(to) + '>';
//
//  DEBUG_PRINTLN(rcpt);
//  client.println(rcpt);

    int cont;
    for (cont = 0; cont < (sizeOfTo + sizeOfCc + sizeOfCCn); cont++) {
        DEBUG_PRINT(F("RCPT TO: <"))
        DEBUG_PRINT(to[cont])
        DEBUG_PRINTLN(F(">"))

        client.print(F("RCPT TO: <"));
        client.print(to[cont]);
        client.println(F(">"));
        awaitSMTPResponse(client);
    }

    DEBUG_PRINTLN(F("DATA:"))
    client.println(F("DATA"));

    response = awaitSMTPResponse(client, 354, "SMTP DATA error");
    if (!response.status) return response;

//  client.println("From: <" + String(this->email_from) + '>');

    client.print(F("From: "));
    if (this->name_from) {
        client.print(this->name_from);
    }
    client.print(F(" <"));
    client.print(this->email_from);
    client.println(F(">"));

//  client.println("To: <" + String(to) + '>');

    client.print(F("To: "));
    for (cont = 0; cont < sizeOfTo; cont++) {
        client.print(F("<"));
        client.print(to[cont]);
        client.print(">");
        if (cont != sizeOfTo - 1) {
            client.print(",");
        }
    }
    client.println();

    if (sizeOfCc > 0) {
        client.print(F("Cc: "));
        for (; cont < sizeOfTo + sizeOfCc; cont++) {
            client.print(F("<"));
            client.print(to[cont]);
            client.print(">");
            if (cont != sizeOfCc - 1) {
                client.print(",");
            }
        }
        client.println();
    }

    if (sizeOfCCn > 0) {
        client.print(F("CCn: "));
        for (; cont < sizeOfTo + sizeOfCc + sizeOfCCn; cont++) {
            client.print(F("<"));
            client.print(to[cont]);
            client.print(">");
            if (cont != sizeOfCCn - 1) {
                client.print(",");
            }
        }
        client.println();
    }
    String subject = "Subject: " + String(email.subject) + "  \r\n";
    subject += "Content-Type: Multipart/mixed; boundary=frontier\r\n";
    subject += "MIME-Version: 1.0\r\n\r\n";

    subject += "--frontier\r\n";

    subject += "Content-Type: ";
    subject += email.mime;
    subject += "; charset=\"GBK\";\r\n\r\n";
//  client.println(F("Content-Type: text/html; charset=\"UTF-8\""));
    // client.println(F("Content-Transfer-Encoding: 8bit"));
    client.print(subject);
    if (email.mime == F("text/html")) {
//	  String body = "<!DOCTYPE html><html lang=\"en\">" + String(email.message) + "</html>";

        client.print(F("<!DOCTYPE html><html lang=\"en\"><HEAD></HEAD><BODY>"));
        client.print(email.message);
        client.println(F("</BODY></html>"));

        //   client.println();
    } else {
        client.println(email.message);
    }
    client.println();

#ifdef STORAGE_INTERNAL_ENABLED
    bool spiffsActive = false;
#endif
#ifdef STORAGE_SD_ENABLED
    bool sdActive = false;
#endif

#if defined(ENABLE_ATTACHMENTS) && (defined(STORAGE_SD_ENABLED) || defined(STORAGE_INTERNAL_ENABLED))
    //  if ((sizeof(attachs) / sizeof(attachs[0]))>0){
    if (attachments.number > 0) {

        DEBUG_PRINT(F("Array: "))
        //	  for (int i = 0; i<(sizeof(attachs) / sizeof(attachs[0])); i++){
        for (int i = 0; i < attachments.number; i++) {
            uint8_t tBuf[64];

            if (attachments.fileDescriptor[i].url.length() == 0) {
                EMailSender::Response response;
                response.code = 400;
                response.desc = "Error no filename specified for the file " + attachments.fileDescriptor[i].filename;
                response.status = false;
                return response;
            }
            if (attachments.fileDescriptor[i].mime.length() == 0) {
                EMailSender::Response response;
                response.code = 400;
                response.desc = "Error no mime type specified for the file " + attachments.fileDescriptor[i].url;
                response.status = false;
                return response;
            }
            if (attachments.fileDescriptor[i].filename.length() == 0) {
                EMailSender::Response response;
                response.code = 400;
                response.desc = "Error no filename specified for the file " + attachments.fileDescriptor[i].url;
                response.status = false;
                return response;
            }

            DEBUG_PRINTLN(attachments.fileDescriptor[i].filename)
            DEBUG_PRINTLN(F("--frontier"))
            client.println(F("--frontier"));
            DEBUG_PRINTLN(F("Content-Type: "))
            client.print(F("Content-Type: "));
            DEBUG_PRINTLN(attachments.fileDescriptor[i].mime)
            client.print(attachments.fileDescriptor[i].mime);
            DEBUG_PRINTLN(F("; charset=\"UTF-8\""))
            client.println(F("; charset=\"UTF-8\""));

            if (attachments.fileDescriptor[i].encode64) {
                client.println(F("Content-Transfer-Encoding: base64"));
            }

            client.print(F("Content-Disposition: attachment; filename="));
            client.print(attachments.fileDescriptor[i].filename);
            client.println(F("\n"));

            int clientCount;

#ifdef STORAGE_INTERNAL_ENABLED
            if (attachments.fileDescriptor[i].storageType == EMAIL_STORAGE_TYPE_SPIFFS ||
                    attachments.fileDescriptor[i].storageType == EMAIL_STORAGE_TYPE_LITTLE_FS ||
                    attachments.fileDescriptor[i].storageType == EMAIL_STORAGE_TYPE_FFAT) {
#ifdef OPEN_CLOSE_INTERNAL
                if (!INTERNAL_STORAGE_CLASS.exists(attachments.fileDescriptor[i].url)) {
                    if (!INTERNAL_STORAGE_CLASS.begin()) {
                        EMailSender::Response response;
                        response.code = 500;
                        response.desc = F("Error on startup filesystem!");
                        response.status = false;
                        return response;
                    }

                    spiffsActive = true;
                    DEBUG_PRINTLN("SPIFFS BEGIN, ACTIVE")
                }
#endif

                int res = INTERNAL_STORAGE_CLASS.open_rdonly(attachments.fileDescriptor[i].url.c_str());
                if (res >= 0) {
                    //					  DEBUG_PRINTLN(myFile.name());
                    if (attachments.fileDescriptor[i].encode64) {
                        encode(&INTERNAL_STORAGE_CLASS, &client);
                    } else {
                        while (INTERNAL_STORAGE_CLASS.available()) {
                            clientCount = INTERNAL_STORAGE_CLASS.read((char *) tBuf, 64);
                            DEBUG_PRINTLN(clientCount)
                            client.write((byte *) tBuf, clientCount);
                        }
                    }
                    INTERNAL_STORAGE_CLASS.close();
                    client.println();
                } else {
                    log_error("Error opening file =%d", res);
                    EMailSender::Response response;
                    response.code = 404;
                    response.desc = "Error opening attachments file " + attachments.fileDescriptor[i].url;
                    response.status = false;
                    return response;
                }

            }
#endif
#ifdef STORAGE_SD_ENABLED
            if (attachments.fileDescriptor[i].storageType==EMAIL_STORAGE_TYPE_SD){
//				File myFile = SD.open(attachments.fileDescriptor[i].url, "r");
//				  if(myFile) {
//					while(myFile.available()) {
//					clientCount = myFile.read(tBuf,64);
//					  client.write((byte*)tBuf,clientCount);
//					}
//					myFile.close();
//				  }
//				  else {
//					  EMailSender::Response response;
//					  response.code = 404;
//					  response.desc = "Error opening attachments file "+attachments.fileDescriptor[i].url;
//					  response.status = false;
//					  return response;
//				  }
#ifdef OPEN_CLOSE_SD
                 DEBUG_PRINTLN(F("SD Check"));
                 if (!SD.exists(attachments.fileDescriptor[i].url.c_str())){
                    if(!SD.begin(SD_CS_PIN)){
                          response.code = 500;
                          response.desc = F("Error on startup SD filesystem!");
                          response.status = false;
                          return response;
                    }
                    sdActive = true;
                 }
#endif

                DEBUG_PRINTLN(F("Open file: "));
            File myFile = SD.open(attachments.fileDescriptor[i].url.c_str());
              if(myFile) {
                  myFile.seek(0);
                  DEBUG_PRINTLN(F("OK"));
                  if (attachments.fileDescriptor[i].encode64){
                      DEBUG_PRINTLN(F("BASE 64"));
                      encode(&myFile, &client);
                  }else{
                      DEBUG_PRINTLN(F("NORMAL"));
                    while(myFile.available()) {
                        clientCount = myFile.read(tBuf,64);
                        client.write((byte*)tBuf,clientCount);
                    }
                  }
                myFile.close();

                client.println();
              }
              else {
                  response.code = 404;
                  response.desc = "Error opening attachments file "+attachments.fileDescriptor[i].url;
                  response.status = false;
                  return response;
              }

            }
#endif

        }
        client.println();
        client.println(F("--frontier--"));
#ifdef STORAGE_SD_ENABLED
#ifdef OPEN_CLOSE_SD
            if (sdActive){
                DEBUG_PRINTLN(F("SD end"));
#ifndef ARDUINO_ESP8266_RELEASE_2_4_2
                SD.end();
#endif
                DEBUG_PRINTLN(F("SD end 2"));
            }
#endif
#endif

#ifdef STORAGE_INTERNAL_ENABLED
#ifdef OPEN_CLOSE_INTERNAL
        if (spiffsActive) {
            INTERNAL_STORAGE_CLASS.end();
            DEBUG_PRINTLN(F("SPIFFS END"))
        }
#endif
#endif

    }

#endif

    DEBUG_PRINTLN(F("Message end"))
    client.println(F("."));

    response = awaitSMTPResponse(client, 250, "Sending message error");
    if (!response.status) return response;

    client.println(F("QUIT"));

    response = awaitSMTPResponse(client, 221, "SMTP QUIT error");
    if (!response.status) return response;

    response.status = true;
    response.code = 0;
    response.desc = F("Message sent!");

    return response;
}

FlashFile lfs_file;
#endif
